﻿using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.Persistent.Base;
using EasyXaf.EntityDesigner.BusinessObjects;
using EasyXaf.EntityDesigner.BusinessObjects.Entities;
using EasyXaf.EntityDesigner.BusinessObjects.Entities.EntityProperties;

namespace EasyXaf.EntityDesigner.Controllers;

public class ChangeDomainModelVersionViewController : ObjectViewController<ListView, DomainModel>
{
    public DomainModel MasterDomainModel { get; set; }

    public SimpleAction ChangeVersionAction { get; }

    public ChangeDomainModelVersionViewController()
    {
        TargetViewId = "DomainModel_ReferenceModels_ListView";

        ChangeVersionAction = new SimpleAction(this, "ChangeVersionAction", PredefinedCategory.View)
        {
            Caption = "更换版本",
            ImageName = "BO_StateMachine",
            SelectionDependencyType = SelectionDependencyType.RequireSingleObject
        };
    }

    protected override void OnActivated()
    {
        base.OnActivated();

        ChangeVersionAction.Execute += ChangeVersionAction_Execute;
    }

    protected override void OnDeactivated()
    {
        ChangeVersionAction.Execute -= ChangeVersionAction_Execute;

        base.OnDeactivated();
    }

    private Entity GetEntity(DomainModel domainModel, string entityName)
    {
        return domainModel.Entities.FirstOrDefault(x => x.Name == entityName);
    }

    private EntityProperty GetEntityProperty(DomainModel domainModel, string entityName, string propertyName)
    {
        return GetEntity(domainModel, entityName)?.Properties.FirstOrDefault(x => x.Name == propertyName);
    }

    private void UpdateToNewDomainModel(DomainModel domainModel)
    {
        using var objectSpace = Application.CreateObjectSpace(typeof(DomainModel));

        var masterDomainModel = objectSpace.GetObject(MasterDomainModel);
        var oldDomainModel = objectSpace.GetObject(ViewCurrentObject);
        var newDomainModel = objectSpace.GetObject(domainModel);

        foreach (var entity in masterDomainModel.Entities)
        {
            if (entity.BaseClass?.DomainModel.Name == newDomainModel.Name)
            {
                entity.BaseClass = GetEntity(newDomainModel, entity.BaseClass.Name);
            }

            if (entity.DefaultProperty?.Entity.DomainModel.Name == newDomainModel.Name)
            {
                entity.DefaultProperty = GetEntityProperty(newDomainModel, entity.Name, entity.DefaultProperty.Name);
            }

            foreach (var property in entity.Properties)
            {
                if (property.EntityType?.DomainModel.Name == newDomainModel.Name)
                {
                    property.EntityType = GetEntity(newDomainModel, property.EntityType.Name);
                }

                if (property.EnumType?.DomainModel.Name == newDomainModel.Name)
                {
                    property.EnumType = newDomainModel.Enums.FirstOrDefault(x => x.Name == property.EnumType.Name);
                }
            }

            foreach (var association in entity.Associations)
            {
                if (association.Parent?.DomainModel.Name == newDomainModel.Name)
                {
                    association.Parent = GetEntity(newDomainModel, association.Parent.Name);
                }

                if (association.ParentProperty?.Entity.DomainModel.Name == newDomainModel.Name)
                {
                    association.ParentProperty = GetEntityProperty(newDomainModel, association.Parent.Name, association.ParentProperty.Name);
                }

                if (association.Child?.DomainModel.Name == newDomainModel.Name)
                {
                    association.Child = GetEntity(newDomainModel, association.Child.Name);
                }

                if (association.ChildProperty?.Entity.DomainModel.Name == newDomainModel.Name)
                {
                    association.ChildProperty = GetEntityProperty(newDomainModel, association.Child.Name, association.ChildProperty.Name);
                }
            }
        }

        foreach (var entityDesign in masterDomainModel.EntityDesigns.ToList())
        {
            if (entityDesign.Entity.DomainModel.Name == newDomainModel.Name)
            {
                entityDesign.Entity = GetEntity(newDomainModel, entityDesign.Entity.Name);
                entityDesign.DomainModel = newDomainModel;
            }
        }

        masterDomainModel.ReferenceModels.Remove(oldDomainModel);
        masterDomainModel.ReferenceModels.Add(newDomainModel);

        objectSpace.CommitChanges();
    }

    private void ChangeVersionAction_Execute(object sender, SimpleActionExecuteEventArgs e)
    {
        var objectSpace = Application.CreateObjectSpace(typeof(DomainModel));
        var viewId = Application.GetListViewId(typeof(DomainModel));
        var collectionSource = Application.CreateCollectionSource(objectSpace, typeof(DomainModel), viewId);
        collectionSource.Criteria["DomainModel"] = CriteriaOperator.Parse("[Oid]!=? And [Name]=?", ViewCurrentObject.Oid, ViewCurrentObject.Name);
        var view = Application.CreateListView(viewId, collectionSource, true);
        Application.ShowViewStrategy.ShowViewInPopupWindow(view, () =>
        {
            if (view.SelectedObjects.Count > 0)
            {
                UpdateToNewDomainModel((DomainModel)view.SelectedObjects[0]);
                ObjectSpace.Refresh();
            }
        });
    }
}
